using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class SelModelInfo
{
    public int id;
    public string modelType;
    public string nameString;
    public Matrix4x4 transformMatrix;
    public string model_path;
    public GameObject model;

    public Vector3 position;
    public Vector3 localScale;
    public Quaternion rotation;

    public void getTransformSDB()
    {
        this.transformMatrix = this.transformMatrix.DxMatrixToApexMatrix();

        this.position = this.transformMatrix.GetPosition();
        Vector3 tScale = this.transformMatrix.GetScale();
        this.localScale = new Vector3(tScale[0]*-1, tScale[1], tScale[2] * -1);
        this.rotation = this.transformMatrix.GetRotation();
        this.localScale *= 0.02f;
        this.position *= 0.02f;
    }

    public void getTransformUnity()
    {
        this.position = new Vector3(transformMatrix.m00, transformMatrix.m10, transformMatrix.m20);
        this.rotation = Quaternion.Euler(new Vector3(transformMatrix.m01, transformMatrix.m11, transformMatrix.m21));

        this.localScale = new Vector3(transformMatrix.m02, transformMatrix.m12, transformMatrix.m22);
    }

    public void getTransformNewModel()
    {
        this.position = this.transformMatrix.GetPosition();
        this.localScale = this.transformMatrix.GetScale();
        this.rotation = this.transformMatrix.GetRotation();
    }
}

public class TargetInfo
{
    public string modelName;
    public int modelId;
}

// NSM: 0-stand, 1-walk, 2-run, 3-carry, 4-open, 5-sit
public enum ActionType
{
    Idle = 0,
    Walk,
    Run,
    Carry,
    Open,
    Sit,
    Turn,
};

public class ActionInfo
{
    public int id;
    public byte actASC;
    public byte actASCBuffer;
    public string style;
    public int objectId;
    public string objectName;
    public int subjectId;
    public string subjectName;
    public bool hasTarget;
    public List<TargetInfo> targets;

    public bool hasStyleObj;
    public List<TargetInfo> styleObjs;

    public List<Interaction> targetsScene;
    public List<Interaction> styleObjsScene;

    // action params
    public bool isCompleted;
    public bool IsSitBegin = false;
    public bool CarryToPlusIdle = false;
    public bool CarryToPlusWalk = false;
    public bool CarryToIdle = false;
    public float timeSitStart = 0f;
    public float timeNow = 0f;
    public bool angleComputed = false;

    // set angles before and after turning to realize turning right
    public Vector3 angleTurnP = new Vector3();
    public Vector3 angleTurnN = new Vector3();

    // 
    public int idxOptim = 0;
    public Matrix4x4 routeLast;
    public List<Matrix4x4> routesOptim;
    public List<Matrix4x4> tarOptim;
    public bool bothMotion;


    public ActionInfo()
    {
        this.id = 0;
        this.actASC = (byte)ActionType.Idle;
        this.actASCBuffer = (byte)ActionType.Idle;
        this.style = null;
        this.subjectId = 0;
        this.subjectName = null;
        this.objectId = 0;
        this.objectName = null;
        this.hasTarget = false;
        this.targets = null;
        this.hasStyleObj = false;
        this.styleObjs = null;
        this.isCompleted = false;
        this.routesOptim = null;
        this.tarOptim = null;
        this.idxOptim = 0;
        this.bothMotion = true;

        this.routeLast = new Matrix4x4();

        this.targetsScene = null;
        this.styleObjsScene = null;
    }
    public ActionInfo(byte asc)
    {
        this.id = 0;
        this.actASC = asc;
        this.actASCBuffer = asc;
        this.style = null;
        this.subjectId = 0;
        this.subjectName = null;
        this.objectId = 0;
        this.objectName = null;
        this.hasTarget = false;
        this.targets = null;
        this.hasStyleObj = false;
        this.styleObjs = null;
        this.isCompleted = false;
        this.routesOptim = null;
        this.tarOptim = null;
        this.idxOptim = 0;
        this.bothMotion = true;

        this.routeLast = new Matrix4x4();

        this.targetsScene = null;
        this.styleObjsScene = null;
    }

    public void ResetStatus(Matrix4x4 model)
    {     
        idxOptim = 0; // 重置搜索最近下标为0
        isCompleted = false;
        IsSitBegin = false;

        CarryToPlusIdle = false;
        CarryToPlusWalk = false;
        CarryToIdle = false;

        // set turn angles
        // angleTurnN = model.localEulerAngles;
        // angleTurnP = model.localEulerAngles;
        angleTurnN = model.GetRotation().eulerAngles;
        angleTurnP = model.GetRotation().eulerAngles;

        // set start time of sit and present time
        timeSitStart = Time.realtimeSinceStartup;
        timeNow = Time.realtimeSinceStartup;

        // look at angle computed
        angleComputed = false;
    }
}

public class Info
{
    public List<SelModelInfo> models;
    public List<ActionInfo> actions;

    public Info(){
        models = new List<SelModelInfo>();
        actions = new List<ActionInfo>();
    }

    public bool targetsNextChanged(int curIdx, int nextIdx)
    {
        if (this.actions[curIdx].targets.Count == this.actions[nextIdx].targets.Count)
        {
            for (int i = 0; i < this.actions[curIdx].targets.Count; i++)
            {
                if (this.actions[curIdx].targets[i].modelId != this.actions[nextIdx].targets[i].modelId)
                {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    public bool targetsNextChangedExceptNone(int curIdx, int nextIdx)
    {
        if (this.actions[nextIdx].targets.Count == 0)
            return false;
        return targetsNextChanged(curIdx, nextIdx);
    }

    public void getInfo()
    {
        int modelNum = 0;
        int actionNum = 0;

        models = new List<SelModelInfo>();
        actions = new List<ActionInfo>();

        String fileName = Params.interfaceFile;
        using (StreamReader sr = new StreamReader(fileName))
        {
            String line = null;
            while ((line = sr.ReadLine()) != null)
            {
                // modelInfo
                if (line.Contains("modelCount"))
                {
                    modelNum = int.Parse(line.Substring(11));
                    for (int i = 0; i < modelNum; i++)
                    {
                        SelModelInfo tM = new SelModelInfo();

                        line = sr.ReadLine();
                        List<String> tp = new List<String>(line.Split(' '));
                        tM.id = int.Parse(tp[1]);
                        tM.nameString = tp[2];
                        if (tp.Count > 3) tM.modelType = tp[3];

                        // String model_path = "Prefabs/scene/" + tM.nameString;
                        string model_path = Params.unityModelPath + tM.nameString;
                        tM.model_path = model_path;

                        //transform
                        line = sr.ReadLine();
                        List<string> tpTrans = new List<String>(line.Split(' '));
                        List<float> tpTFloat = new List<float>();
                        for (int j = 0; j < tpTrans.Count - 1; j++)
                        {
                            tpTFloat.Add((float)Convert.ToSingle(tpTrans[j + 1]));
                        }
                        tM.transformMatrix = new Matrix4x4(new Vector4(tpTFloat[0], tpTFloat[1], tpTFloat[2], tpTFloat[3]),
                            new Vector4(tpTFloat[4], tpTFloat[5], tpTFloat[6], tpTFloat[7]),
                            new Vector4(tpTFloat[8], tpTFloat[9], tpTFloat[10], tpTFloat[11]),
                            new Vector4(tpTFloat[12], tpTFloat[13], tpTFloat[14], tpTFloat[15]));

                        //tM.getTransformSDB();
                        //tM.getTransformUnity();
                        tM.getTransformNewModel();


                        models.Add(tM);
                    }
                }

                // actionInfo
                if (line.Contains("actionCount"))
                {
                    actionNum = int.Parse(line.Substring(12));
                    for (int i = 0; i < actionNum; i++)
                    {
                        List<TargetInfo> targets = new List<TargetInfo>();

                        ActionInfo tA = new ActionInfo();
                        line = sr.ReadLine();
                        List<String> ta = new List<String>(line.Split(' '));


                        tA.id = int.Parse(ta[1]);
                        if (ta.Count > 3)
                            tA.style = ta[3];

                        //27-ESC, 10-shift
                        switch (ta[2])
                        {
                            case "sit":
                                tA.actASC = (byte)ActionType.Sit;
                                break;
                            case "carry":
                                tA.actASC = (byte)ActionType.Carry;
                                break;
                            case "open":
                                tA.actASC = (byte)ActionType.Open;
                                break;
                            case "walk":
                                tA.actASC = (byte)ActionType.Walk;
                                break;
                            case "turn":
                                tA.actASC = (byte)ActionType.Turn;
                                break;
                            case "run":
                                tA.actASC = (byte)ActionType.Run;
                                break;
                            default:
                                tA.actASC = (byte)ActionType.Idle;
                                break;
                        }

                        // subject
                        line = sr.ReadLine();
                        List<String> sub = new List<string>(line.Split(' '));
                        if (sub[1] != "null")
                        {
                            tA.subjectName = sub[1];
                            tA.subjectId = int.Parse(sub[2]);
                        }


                        // object
                        line = sr.ReadLine();
                        List<String> to = new List<string>(line.Split(' '));
                        if (to[1] != "null")
                        {
                            tA.objectName = to[1];
                            tA.objectId = int.Parse(to[2]);
                        }


                        // Target
                        line = sr.ReadLine();
                        List<String> tl = new List<String>(line.Split(' '));
                        int targetNum = int.Parse(tl[1]);
                        if (targetNum > 0)
                            tA.hasTarget = true;

                        List<TargetInfo> tList = new List<TargetInfo>();
                        TargetInfo tT = new TargetInfo();
                        for (int j = 0; j < targetNum; j++)
                        {
                            tT = new TargetInfo();
                            line = sr.ReadLine();
                            List<String> tt = new List<String>(line.Split(' '));
                            tT.modelName = tt[0];
                            tT.modelId = int.Parse(tt[1]);

                            tList.Add(tT);
                        }
                        tA.targets = tList;

                        // Style Object
                        line = sr.ReadLine();
                        List<String> ttl = new List<String>(line.Split(' '));
                        int styleObjectNum = int.Parse(ttl[1]);
                        if (styleObjectNum > 0)
                            tA.hasStyleObj = true;
                        
                        List<TargetInfo> ttList = new List<TargetInfo>();
                        TargetInfo ttT = new TargetInfo();
                        for (int j = 0; j < styleObjectNum; j++)
                        {
                            ttT = new TargetInfo();
                            line = sr.ReadLine();
                            List<String> ttt = new List<String>(line.Split(' '));
                            ttT.modelName = ttt[0];
                            ttT.modelId = int.Parse(ttt[1]);

                            ttList.Add(ttT);
                        }
                        tA.styleObjs = ttList;

                        tA.actASCBuffer = tA.actASC;
                        actions.Add(tA);
                    }
                }
            }
        }

        if (actionNum == 0)
        {
            //init an empty action
            actions.Add(new ActionInfo());
        }
    }

}